package com.xjnt.frameworks.plugin.entity;

import java.util.List;

import com.google.common.collect.Lists;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log4jLogger;
import com.jfinal.log.Logger;
import com.jfinal.plugin.IPlugin;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.Model;
import com.xjnt.frameworks.annotation.Entity;
import com.xjnt.frameworks.plugin.entity.naming.INameStyle;
import com.xjnt.frameworks.utils.ClasserKit;
import com.xjnt.frameworks.utils.ReflectKit;

public class EntityPlugin implements IPlugin{
	
	private static final Logger logger = Log4jLogger.getLogger(EntityPlugin.class);

	private boolean isStarted = false;
	private ActiveRecordPlugin arp;
	private INameStyle nameStyle;

	/**
	 * 是否扫描library库中的所有Jar包
	 */
	private boolean includeAllJarsInLib = false;
	/**
	 * 需要扫描的包路径集合
	 */
	private List<String> includePackages = Lists.newArrayList();
	/**
	 * 需要扫描的Jar包路径集合
	 */
	private List<String> includeJars = Lists.newArrayList();
	/**
	 * 需要过滤的类集合
	 */
	private List<Class<? extends Model<?>>> excludeClasses = Lists.newArrayList();
	
	
	public EntityPlugin(ActiveRecordPlugin arp){
		this.arp = arp;
	}
	
	public EntityPlugin setNameStyle(INameStyle nameStyle) {
		this.nameStyle = nameStyle;
		return this;
	}

	public EntityPlugin addScanPackages(String... packages) {
		for (String pkg : packages) {
			includePackages.add(pkg);
		}
		return this;
	}
	
	public EntityPlugin addIncludeJars(String... jars){
		for (String jar : jars) {
			includeJars.add(jar);
		}
		return this;
	}
	
	public EntityPlugin addIncludeJars(List<String> jars){
		if(null != jars && !jars.isEmpty()){
			includeJars.addAll(jars);
		}
		return this;
	}

	@SuppressWarnings("unchecked")
	public EntityPlugin addExcludeClasses(Class<? extends Model<?>>... clazzes) {
		for (Class<? extends Model<?>> clazz : clazzes) {
			excludeClasses.add(clazz);
		}
		return this;
	}

	public EntityPlugin addExcludeClasses(List<Class<? extends Model<?>>> clazzes) {
		if (null != clazzes && !clazzes.isEmpty()) {
			excludeClasses.addAll(clazzes);
		}
		return this;
	}
	
	public void build(){
		List<Class<? extends Model<?>>> modelClasses = ClasserKit.of(Model.class)
				.includeAllJarsInLib(includeAllJarsInLib).injars(includeJars)
				.scanPackages(includePackages).search();
		String configName = ReflectKit.on(arp).get("configName");
		Entity entity;
		for (Class<? extends Model<?>> modelClass : modelClasses) {
			if (excludeClasses.contains(modelClass)) {
				continue;
			}
			entity = modelClass.getAnnotation(Entity.class);
			String tableName;
			if (null == entity) {
				tableName = nameStyle.name(modelClass.getSimpleName());
				arp.addMapping(tableName, modelClass);
				logger.debug(configName + " addMapping(" + tableName + ", " + modelClass + ")");
			} else {
				String configAsName = entity.configName();
				if (StrKit.notBlank(configAsName) && !configAsName.equals(configName)) {
					continue;
				}
				tableName = entity.tableName();
				String primaryKey = entity.primaryKey();
				if (StrKit.notBlank(primaryKey)) {
					arp.addMapping(tableName, primaryKey, modelClass);
					logger.debug(configName + " addMapping(" + tableName + ", " + primaryKey + ", " + modelClass + ")");
				} else {
					arp.addMapping(tableName, modelClass);
					logger.debug(configName + " addMapping(" + tableName + ", " + modelClass + ")");
				}
			}
		}
	}
	
	public void destory(){
		this.includeJars.clear();
		this.includePackages.clear();
		this.excludeClasses.clear();
	}

	@Override
	public boolean start() {
		if( isStarted ){
			return true;
		}
		build();
		return true;
	}

	@Override
	public boolean stop() {
		destory();
		return true;
	}
}
